Modern digital data processors are often pipelined, meaning that execution of each instruction is divided into several stages. Such stages may include, by way of example, a fetch stage, a decode stage, an execute stage, and a writeback stage. The execute stage may comprise multiple specialized execution units, such as multipliers, adders or dividers, for performing integer or floating point arithmetic operations.
It is often desirable for a real-time application, running on a pipelined digital data processor or other type of digital data processor, to execute its software in a deterministic manner. However, interrupts can occur at unexpected times to change the flow of software execution. If an application has time-critical tasks that must execute before a given deadline, either the interrupts must be disabled and then reenabled, or complex analysis must be performed to determine if the deadline can be met despite the interrupts.
Interrupts for a central processing unit (CPU) in a pipelined digital data processor are typically processed using a state machine that controls the pipeline to redirect execution to an interrupt handler in response to designated events. The interrupt handler is usually implemented in software.
As indicated previously, one typical conventional mechanism for managing interrupts is through enabling or disabling the interrupts. This capability may be implemented with CPU instructions or through toggling control register bits in an interrupt controller, in conjunction with utilization of the above-noted state machine.
A problem with this approach is that the state machine used to implement the interrupt function adds significant complexity to the processor pipeline. The pipeline must be designed to accept commands from the state machine rather than from an operational, non-interrupt instruction fetch path. The state machine may interrupt the pipeline in any state. Thus, it must preserve several program counters to allow the pipeline to be restarted at the point of the interrupt. This requires additional logic circuitry in the processor, as well as additional development time for functional verification, both of which increase processor cost.
Another problem relates to the fact that the CPU instructions that enable or disable interrupts typically change a control bit in a CPU control or status register. As a result, the enabling of interrupts usually takes at least one clock cycle, and the disabling of interrupts also takes at least one clock cycle. These two cycles increase the overhead for handling an interrupt, especially for the case of short interrupt routines. Although pipelined processors often handle read and write hazards for frequently-used general-purpose registers, hazards for accesses to control or status registers are not typically handled. Thus, it is the responsibility of the application software programmer to schedule any such interrupt enabling or disabling instructions with others that may be in the pipeline at the same time.
It is also possible to use a real-time operating system (RTOS) to schedule processing tasks associated with real-time applications. The RTOS handles dispatching tasks and implements other services to ensure that deadlines for time-critical tasks are met. However, using an RTOS to enforce deterministic software execution typically requires a processor of substantial size, cost and complexity. The use of an RTOS to provide deterministic execution in applications involving simple software architectures therefore leads to unnecessary increases in implementation expense and performance overhead.
Accordingly, a need exists for improved techniques for handling interrupts in a pipelined processor or other type of processor.